package com.vains.db.util;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.vains.db.model.GeneratorRes;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 自定义代码生成器，继承自Mybatis-plus的代码生成器
 *
 * @author vains
 * @version 1.0
 * @since 2020/6/3 22:16
 **/
@Slf4j
class MyAutoGenerator extends AutoGenerator {

    /**
     * 生成预览内容 不生成文件
     *
     * @return 返回数据
     */
    List<List<GeneratorRes>> processTemplateToString() {
        log.debug("==========================准备生成文件...==========================");
        // 初始化配置
        if (null == config) {
            config = new ConfigBuilder(super.getPackageInfo(), super.getDataSource(), super.getStrategy(), super.getTemplate(), super.getGlobalConfig());
            if (null != injectionConfig) {
                injectionConfig.setConfig(config);
            }
        }
        if (null == super.getTemplateEngine()) {
            // 为了兼容之前逻辑，采用 Velocity 引擎 【 默认 】
            super.setTemplateEngine(new VelocityTemplateEngine());
        }
        // 模板引擎初始化执行文件输出
        AbstractTemplateEngine templateEngine = super.getTemplateEngine();
        templateEngine.init(pretreatmentConfigBuilder(config));
        List<TableInfo> tableInfoList = templateEngine.getConfigBuilder().getTableInfoList();
        List<List<GeneratorRes>> lists = new ArrayList<>();
        for (TableInfo tableInfo : tableInfoList) {
            List<GeneratorRes> list = new ArrayList<>();
            Map<String, Object> objectMap = templateEngine.getObjectMap(tableInfo);
            Map<String, String> pathInfo = templateEngine.getConfigBuilder().getPathInfo();
            TemplateConfig template = templateEngine.getConfigBuilder().getTemplate();
            // 自定义内容
            InjectionConfig injectionConfig = templateEngine.getConfigBuilder().getInjectionConfig();
            if (null != injectionConfig) {
                injectionConfig.initTableMap(tableInfo);
                objectMap.put("cfg", injectionConfig.getMap());
                List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
                if (CollectionUtils.isNotEmpty(focList)) {
                    for (FileOutConfig foc : focList) {
                        createGenerator(objectMap, templateEngine, foc.outputFile(tableInfo), list, "other", foc.getTemplatePath());
                    }
                }
            }
            // Mp.java
            String entityName = tableInfo.getEntityName();
            if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
                String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
                createGenerator(objectMap, templateEngine, entityFile, list, "Entity", template.getEntity(templateEngine.getConfigBuilder().getGlobalConfig().isKotlin()));
            }
            // MpMapper.java
            if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
                String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
                createGenerator(objectMap, templateEngine, mapperFile, list, "Mapper", template.getMapper());
            }
            // MpMapper.xml
            if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
                String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
                createGenerator(objectMap, templateEngine, xmlFile, list, "mapperXml", template.getXml());
            }
            // IMpService.java
            if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
                String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
                createGenerator(objectMap, templateEngine, serviceFile, list, "IService", template.getService());
            }
            // MpServiceImpl.java
            if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
                String implFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
                createGenerator(objectMap, templateEngine, implFile, list, "ServiceImpl", template.getServiceImpl());
            }
            // MpController.java
            if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
                String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
                createGenerator(objectMap, templateEngine, controllerFile, list, "Controller", template.getController());
            }
            lists.add(list);
        }
        log.debug("==========================预览内容生成完成！！！==========================");
        return lists;
    }

    /**
     * 文件后缀
     */
    private String suffixJavaOrKt() {
        return super.getTemplateEngine().getConfigBuilder().getGlobalConfig().isKotlin() ? ConstVal.KT_SUFFIX : ConstVal.JAVA_SUFFIX;
    }

    /**
     * 获取内容
     *
     * @param objectMap    数据
     * @param templatePath 模板路径
     * @return 返回内容
     */
    private String getStringFromTemplate(Map<String, Object> objectMap, String templatePath) {
        String preStr = null;
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        configuration.setDefaultEncoding(ConstVal.UTF8);
        configuration.setClassForTemplateLoading(FreemarkerTemplateEngine.class, StringPool.SLASH);
        try {
            Template template = configuration.getTemplate(templatePath);
            preStr = FreeMarkerTemplateUtils.processTemplateIntoString(template, objectMap);
        } catch (IOException | TemplateException e) {
            log.error("预览文件生成失败，请稍后重试！");
        }
        return preStr;
    }

    /**
     * 创建 GeneratorRes 并放入集合中
     *
     * @param objectMap      数据
     * @param templateEngine 模板
     * @param filePath       文件路径
     * @param list           集合
     * @param type           类型
     */
    private void createGenerator(Map<String, Object> objectMap, AbstractTemplateEngine templateEngine, String filePath, List<GeneratorRes> list, String type, String templateType) {
        GeneratorRes res = new GeneratorRes();
        String content;
        if (Objects.equals("other", type)) {
            content = getStringFromTemplate(objectMap, templateType);
        } else {
            content = getStringFromTemplate(objectMap, templateEngine.templateFilePath(templateType));
        }
        res.setName(new File(filePath).getName());
        res.setContent(content);
        res.setType(type);
        list.add(res);
    }

}
